#include "../HWJpegDecoder.h"

// 分块解码，更节省RAM空间，可以在RAM紧张的情况下使用(默认设置)
// 分块输入: 解码时一块一块读取输入解码，块大小请设置HWJpegDecoder::defaultInputBufferSize的值
// 分块输出: 解码时一块一块读取输入解码，块大小请设置HWJpegDecoder::defaultOutputBufferSize的值
// 分块输出时，还需要使用setOutputCallback()设置输出回调函数，用于处理解码后输出的数据。

// 分块输入和输出可以独立配置，比如可以配置整个文件输入，但是分块解码输出

static void DMA2D_Copy_YCbCr_To_RGB(uint32_t pSrc, uint32_t pdst, uint16_t x, uint16_t y, uint16_t xsize, uint16_t ysize, uint32_t ChromaSampling);

// JPEG图像源数组
static const uint8_t jpegSource[] = { ... };

void decodeJPEGFromMem(void)
{
    HWJpegDecoder *jpegDecoder = new HWJpegDecoder(&hjpeg);

    jpegDecoder->setFullInput(false);    // 分块输入(默认设置，可以不调用)
    jpegDecoder->setFullOutput(false);   // 分块输出(默认设置，可以不调用)

    // 分块输出时设置回调函数
    jpegDecoder->setOutputCallback(
        [](HWJpegDecoder::ImageInfo &info, const void *data, uint32_t line, uint32_t numOfLine) // lambda
        {
            // YCbCr 转RGB
            DMA2D_Copy_YCbCr_To_RGB(
                (uint32_t)data,
                (uint32_t)canvasBuffer,
                0,
                line * info.MCUHeight,
                info.width,
                numOfLine * info.MCUHeight,
                info.chromaSubsampling);
        });

    jpegDecoder->setInputDataSource(jpegSource, sizeof(jpegSource));
    // jpegDecoder->setInputDataSource("0:/jpeg/test.jpg");

    int ret = jpegDecoder->decode();
    if (ret == HWJpegDecoder::NoError)
    {
        jpegDecoder->waitDecodeFinish();    // 阻塞等待解码完成

        HWJpegDecoder::ImageInfo &info = jpegDecoder->getImageInfo();
        // printf("height = %ld\r\n", info.height);
        // printf("width = %ld\r\n", info.width);
    }

    // jpegDecoder->reset();    // 若还需要继续解码请reset()释放内存，否则会导致内存泄漏
    
    delete jpegDecoder;     // 删除解码器
}

static void DMA2D_Copy_YCbCr_To_RGB(uint32_t pSrc, uint32_t pdst, uint16_t x, uint16_t y, uint16_t xsize, uint16_t ysize, uint32_t ChromaSampling)
{
	uint32_t cssMode = DMA2D_CSS_420;
	uint32_t inputLineOffset = 0;
	uint32_t destination = 0;

	/* 处理输入行偏移 */
	switch (ChromaSampling)
	{
	case JPEG_420_SUBSAMPLING:
		cssMode = DMA2D_CSS_420;
		inputLineOffset = xsize % 16;
		if (inputLineOffset != 0)
			inputLineOffset = 16 - inputLineOffset;
		break;
	case JPEG_444_SUBSAMPLING:
		cssMode = DMA2D_NO_CSS;
		inputLineOffset = xsize % 8;
		if (inputLineOffset != 0)
			inputLineOffset = 8 - inputLineOffset;
		break;
	case JPEG_422_SUBSAMPLING:
		cssMode = DMA2D_CSS_422;
		inputLineOffset = xsize % 16;
		if (inputLineOffset != 0)
			inputLineOffset = 16 - inputLineOffset;
		break;
	default:;
	}

	destination = (uint32_t)pdst + ((y * 320) + x) * 2; // 输出地址，末尾乘以2对应RGB565

	DMA2D->CR = 0x00010000UL | (1 << 9); // 存储器到存储器模式
	DMA2D->OOR = 320 - xsize;

	/* 输出格式 */
	DMA2D->OPFCCR = LTDC_PIXEL_FORMAT_RGB565 | (DMA2D_REGULAR_ALPHA << 20) | (DMA2D_RB_REGULAR << 21);

	/* 前景层输入格式 */
	DMA2D->FGPFCCR = DMA2D_INPUT_YCBCR | (DMA2D_REPLACE_ALPHA << 16) | (DMA2D_REGULAR_ALPHA << 20) | (DMA2D_RB_REGULAR << 21) | (0xFFU << 24) | (cssMode << 18);

	DMA2D->FGOR = inputLineOffset;
	DMA2D->NLR = (uint32_t)(xsize << 16) | (uint16_t)ysize;
	DMA2D->OMAR = (uint32_t)destination;
	DMA2D->FGMAR = (uint32_t)pSrc;

	DMA2D->CR |= DMA2D_CR_START; // 启动传输

	while (DMA2D->CR & DMA2D_CR_START)
		; //	等待传输完成
}
